package vip.aster.monitor.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.Cache;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import vip.aster.common.constant.CacheConstants;
import vip.aster.common.utils.CacheUtils;
import vip.aster.common.utils.ResultInfo;
import vip.aster.monitor.vo.CacheVO;

import java.util.*;

/**
 * 缓存监控
 *
 * @author Aster
 * @since 2024/2/5 18:07
 */
@RestController
@RequestMapping("/monitor/cache")
@AllArgsConstructor
@Tag(name = "缓存监控")
public class CacheController {
    private static String tmpCacheName = "";

    private final static List<CacheVO> CACHES = new ArrayList<>();

    static {
        CACHES.add(new CacheVO(CacheConstants.LOGIN_TOKEN_KEY, "用户信息"));
        CACHES.add(new CacheVO(CacheConstants.CAPTCHA_CODE_KEY, "验证码"));
        CACHES.add(new CacheVO(CacheConstants.SYS_CONFIG_KEY, "配置信息"));
        CACHES.add(new CacheVO(CacheConstants.SYS_DICT_KEY, "数据字典"));
        CACHES.add(new CacheVO(CacheConstants.REPEAT_SUBMIT_KEY, "防重提交"));
        CACHES.add(new CacheVO(CacheConstants.RATE_LIMIT_KEY, "限流处理"));
        CACHES.add(new CacheVO(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数"));
    }

    @GetMapping("/all")
    @Operation(summary = "缓存信息")
    @PreAuthorize("hasAuthority('monitor:cache:all')")
    public ResultInfo<Map<String, Object>> getInfo() {
        Map<String, Object> result = new HashMap<>(3);
        if (CacheUtils.getCacheManager() instanceof RedisCacheManager) {
            // Step 1: 获取Redis详情
            Properties info = (Properties) CacheUtils.getRedisTemplate().execute((RedisCallback<Object>) connection -> connection.info());
            Properties commandStats = (Properties) CacheUtils.getRedisTemplate().execute((RedisCallback<Object>) connection -> connection.info("commandstats"));
            // Step 2: 获取Key的数量
            Object dbSize = CacheUtils.getRedisTemplate().execute((RedisCallback<Object>) connection -> connection.dbSize());
            result.put("info", info);
            result.put("keyCount", dbSize);
            // Step 3: 获取请求次数
            List<Map<String, String>> pieList = new ArrayList<>();
            if (commandStats != null && !commandStats.isEmpty()) {
                commandStats.stringPropertyNames().forEach(key -> {
                    Map<String, String> data = new HashMap<>(2);
                    String property = commandStats.getProperty(key);
                    data.put("name", StringUtils.removeStart(key, "cmdstat_"));
                    data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
                    pieList.add(data);
                });
                result.put("commandStats", pieList);
            }
        }
        return ResultInfo.success(result);
    }

    @GetMapping("/getNames")
    @Operation(summary = "缓存列表")
    @PreAuthorize("hasAuthority('monitor:cache:all')")
    public ResultInfo<List<CacheVO>> cache() {
        return ResultInfo.success(CACHES);
    }

    @GetMapping("/getKeys/{cacheName}")
    @Operation(summary = "获取缓存下所有key")
    @PreAuthorize("hasAuthority('monitor:cache:all')")
    public ResultInfo<Set<String>> getCacheKeys(@PathVariable String cacheName) {
        tmpCacheName = cacheName;
        Set<String> keyset = CacheUtils.keys(cacheName);
        return ResultInfo.success(keyset);
    }

    @GetMapping("/getValue/{cacheName}/{cacheKey}")
    @Operation(summary = "获取缓存值")
    @PreAuthorize("hasAuthority('monitor:cache:all')")
    public ResultInfo<CacheVO> getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey) {
        Cache.ValueWrapper valueWrapper = CacheUtils.get(cacheName, cacheKey);
        CacheVO cacheVO = new CacheVO();
        cacheVO.setCacheName(cacheName);
        cacheVO.setCacheKey(cacheKey);
        if (valueWrapper != null) {
            Object value = valueWrapper.get();
            cacheVO.setCacheValue(value == null ? "" : value.toString());
        }
        return ResultInfo.success(cacheVO);
    }

    @GetMapping("/clearCacheName/{cacheName}")
    @Operation(summary = "删除缓存下所有key")
    @PreAuthorize("hasAuthority('monitor:cache:delete')")
    public ResultInfo<String> clearCacheName(@PathVariable String cacheName) {
        CacheUtils.clear(cacheName);
        return ResultInfo.success();
    }

    @GetMapping("/clearCacheKey/{cacheKey}")
    @Operation(summary = "删除缓存下某一个key")
    @PreAuthorize("hasAuthority('monitor:cache:delete')")
    public ResultInfo<String> clearCacheKey(@PathVariable String cacheKey) {
        CacheUtils.deleteIfPresent(tmpCacheName, cacheKey);
        return ResultInfo.success();
    }

    @GetMapping("/clearCacheAll")
    @Operation(summary = "删除所有缓存")
    @PreAuthorize("hasAuthority('monitor:cache:delete')")
    public ResultInfo<String> clearCacheAll() {
        for (String cacheName : CacheUtils.getCacheManager().getCacheNames()) {
            CacheUtils.clear(cacheName);
        }
        return ResultInfo.success();
    }
}
